﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.IO.Packaging;

namespace OPCDiffCore
{
    /// <summary>
    /// Util class to compare two OPC (Open Packaging Convention) packages.
    /// </summary>
    public sealed class OPCDiffer
    {
        /// <summary>
        /// Compare two OPC packages logically ('AnalyzeDetail' set to 'Logical'.
        /// </summary>
        /// <param name="pkgOriginal">The original package to compare.</param>
        /// <param name="pkgDiff">The package to compare against the original.</param>
        /// <returns><b>true</b> if the packages are equal, else <b>false</b>.</returns>
        public bool Equals(Package pkgOriginal, Package pkgDiff)
        {
            PackageDiff packageDiff = GetPackageDiff(pkgOriginal, pkgDiff, AnalyzeLevel.Logical);
            return packageDiff.CountPartDiff == 0;
        }

        /// <summary>
        /// Compare two OPC packages.
        /// </summary>
        /// <param name="pathOriginal">Path of the original package to compare.</param>
        /// <param name="pathDiff">Path of the package to compare against the original.</param>
        /// <returns><b>true</b> if the packages are equal, else <b>false</b>.</returns>
        public bool Equals(string pathOriginal, string pathDiff, AnalyzeLevel analyzeDetail)
        {
            PackageDiff packageDiff = GetPackageDiff(pathOriginal, pathDiff, analyzeDetail);
            return packageDiff.CountPartDiff == 0;
        }

        /// <summary>
        /// Gets the package differences from the two specified package.
        /// </summary>
        /// <param name="pkgOriginal">The package considered to be the original one.</param>
        /// <param name="pkgDiff">The package tested against the original one.</param>
        /// <returns></returns>
        public PackageDiff GetPackageDiff(string pathOriginal, string pathDiff, AnalyzeLevel checkDetail)
        {
            AnalyzeConfiguration config = new AnalyzeConfiguration {
                OriginalFile = pathOriginal,
                CompareFile = pathDiff,
                AnalyzeLevel = checkDetail
            };
            return GetAnalyzeModule(checkDetail).RunAnalyze(config);
        }

        /// <summary>
        /// Gets the package differences.
        /// </summary>
        /// <param name="pkgOriginal">Source package to compare.</param>
        /// <param name="pkgDiff">Tager package to compare against the source.</param>
        /// <param name="checkDetail">The level of difference to return.</param>
        private PackageDiff GetPackageDiff(Package pkgOriginal, Package pkgDiff, AnalyzeLevel analyzeLevel)
        {
            if (analyzeLevel == AnalyzeLevel.Physical)
                throw new InvalidOperationException("You can't run a physical comparaison with this method !");

            AnalyzeConfiguration config = new AnalyzeConfiguration
            {
                OriginalPackage = pkgOriginal,
                ComparePackage = pkgDiff,
                AnalyzeLevel = analyzeLevel
            };
            return GetAnalyzeModule(analyzeLevel).RunAnalyze(config);
        }

        /// <summary>
        /// Provides the corresponding AnalyzeModule according to the specified analyse level.
        /// </summary>
        private IAnalyzeModule GetAnalyzeModule(AnalyzeLevel detail)
        {
            switch (detail)
            {
                case AnalyzeLevel.Physical:
                    return new PhysicalAnalyzeModule();

                default:
                    return new LogicalAnalyzeModule();
            }
        }
    }

    /// <summary>
    /// Event arguments for part related events.
    /// </summary>
    public class PartEventArgs : EventArgs
    {
        public PackagePart AnalyzePart { get; set; }
    }
}
